package service;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by fanzhenyu02 on 2020/8/29.
 */
public class FileSplitService {


    public static final String fileCharSet = "UTF-8";

    public static final String fileSeparator = "_";


    /**
     * 按行分割大文件为多个小文件
     *
     * @param sourceFileName
     * @param splitSize
     */
    public static void splitFileByLine(String sourceFileName, int splitSize) {
        int rowPerFile = ((int) Math.ceil(getFileLineNum(sourceFileName) / (double) splitSize));
        long startTime = System.currentTimeMillis();

        PrintWriter printWriter = null;//字符输出流
        String tempLine;
        int lineNum = 0;//本次行数累计 , 达到rows开辟新文件
        int splitFileIndex = 1;//当前文件索引

        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFileName)))) {
            String splitFileName = sourceFileName + fileSeparator + splitFileIndex;
            printWriter = new PrintWriter(splitFileName);
            while ((tempLine = br.readLine()) != null) {
                if (lineNum > 0 && lineNum % rowPerFile == 0) {
                    // 需要转换到写新文件
                    printWriter.flush();
                    printWriter.close();
                    ++splitFileIndex;
                    printWriter = new PrintWriter(sourceFileName + fileSeparator + splitFileIndex);
                }

                printWriter.write(tempLine + "\n");
                lineNum++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != printWriter) {
                printWriter.flush();
                printWriter.close();
            }

            System.out.println("split by line total consume time ：" + (System.currentTimeMillis() - startTime) + " ms.");
        }
    }

    /**
     * 获取大文件的行数
     *
     * @param fileName
     * @return
     */
    public static int getFileLineNum(String fileName) {
        try (LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(fileName))) {
            lineNumberReader.skip(Long.MAX_VALUE);
            int lineNumber = lineNumberReader.getLineNumber();
            return lineNumber;//实际上是读取换行符数量 , 所以需要+1
        } catch (IOException e) {
            return -1;
        }
    }

    /**
     * 按文件大小拆分文件为多个小文件
     *
     * @param filePath
     * @param splitCount
     * @throws IOException
     */
    public static void splitFileBySize(String filePath, int splitCount) {
        long startTime = System.currentTimeMillis();
        try (
                FileInputStream fis = new FileInputStream(filePath);
                FileChannel inputChannel = fis.getChannel();
        ) {
            final long fileSize = inputChannel.size();
            long average = ((long) Math.ceil(fileSize / splitCount));//平均值
            long bufferSize = 256; //缓存块大小，自行调整
            ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.valueOf(bufferSize + "")); // 申请一个缓存区
            long startPosition = 0; //子文件开始位置
            long endPosition = average < bufferSize ? 0 : average - bufferSize;//子文件结束位置
            for (int i = 0; i < splitCount; i++) {
                if (i + 1 != splitCount) {
                    int read = inputChannel.read(byteBuffer, endPosition);// 读取数据
                    readW:
                    while (read != -1) {
                        byteBuffer.flip();//切换读模式
                        byte[] array = byteBuffer.array();
                        for (int j = 0; j < array.length; j++) {
                            byte b = array[j];
                            if (b == 10 || b == 13) { //判断\n\r
                                endPosition += j;
                                break readW;
                            }
                        }
                        endPosition += bufferSize;
                        byteBuffer.clear(); //重置缓存块指针
                        read = inputChannel.read(byteBuffer, endPosition);
                    }
                } else {
                    endPosition = fileSize; //最后一个文件直接指向文件末尾
                }

                try (
                        FileOutputStream fos = new FileOutputStream(filePath + "=" + (i + 1));
                        FileChannel outputChannel = fos.getChannel();
                ) {
                    inputChannel.transferTo(startPosition, endPosition - startPosition, outputChannel);//通道传输文件数据
                } catch (Exception e) {
//                    logHandler.logErrObj("split file write to file error!", e);
                }

                startPosition = endPosition + 1;
                endPosition += average;
            }
        } catch (Exception e) {
//            logHandler.logErrObj("split file error!", e);
        }

        System.out.println("split by size total consume time ：" + (System.currentTimeMillis() - startTime) + " ms.");

    }


    public static void main(String[] args) {
//        System.out.println(getFileLineNum("/Users/vonmax/Downloads/testTotalFile.txt"));

        splitFileByLine("/Users/vonmax/Downloads/20200808_01_AC_COMTRX.txt", 4);
        splitFileBySize("/Users/vonmax/Downloads/20200808_01_AC_COMTRX.txt", 4);

    }


}
